package com.ust.tk.simpletool;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import android.os.Bundle;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Menu;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.Camera.Size;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;

import android.view.MenuItem;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.widget.TextView;
import android.hardware.Camera;

public class CompassActivity extends Activity implements SensorEventListener {

	private TextView degreeText;
	private CompassView surfaceView;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_compass);

		degreeText = (TextView)findViewById(R.id.textView1);
		surfaceView = (CompassView)findViewById(R.id.surfaceView1);
		initSensor();
	}

	@Override
	protected void onResume() {
		super.onResume();
		resumeSensor();
	}
	@Override
	protected void onPause() {
		super.onPause();
		releaseSensor();
	}
	@Override
	protected void onStop() {
		super.onStop();
		releaseSensor();
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.compass, menu);
		return true;
	}
	boolean mEnableCamera;
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
	    // Handle item selection
	    switch (item.getItemId()) {
	    case R.id.action_camera:
	    	boolean mEnableCamera = !item.isChecked();
	    	item.setChecked(mEnableCamera);
	        return true;
	    default:
	        return super.onOptionsItemSelected(item);
	    }
	}


	//
	// Sensor handling
	//
	private SensorManager sensorManager = null;
	private Sensor accelerometer = null;
	private Sensor magnetometer = null;
	
	long lastUpdate;
	
	float[] mGravity;
	float[] mGeomagnetic;

    float R3x3[] = new float[9];
    float I3x3[] = new float[9];
    float orientation[] = new float[3];
    float azimut = 0f;

	private void initSensor() {
		sensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
		accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
		if ( accelerometer == null ) {
			Log.e("", "No Sensor.TYPE_ACCELEROMETER on the device...");
		}
		magnetometer = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
		if ( magnetometer == null ) {
			Log.e("", "No Sensor.TYPE_MAGNETIC_FIELD on the device...");
		}
		
		lastUpdate = System.currentTimeMillis();
	}
	private void releaseSensor() {
		if ( sensorManager != null )
			sensorManager.unregisterListener(this);
	}
	
	private void resumeSensor() {
		if ( accelerometer != null &&
			sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_NORMAL) ) 
		{
			Log.i("", "Accelerometer listener's been registered.");
		}
		if ( magnetometer != null  && 
			sensorManager.registerListener(this, magnetometer, SensorManager.SENSOR_DELAY_NORMAL) )
		{
			Log.i("", "Magnetic field listener's been registered.");
		}

	}

	@Override
	public void onSensorChanged(SensorEvent evt) {
		switch ( evt.sensor.getType() ) {
		case Sensor.TYPE_ACCELEROMETER:
			mGravity = evt.values;
			break;
		case Sensor.TYPE_MAGNETIC_FIELD:
			mGeomagnetic = evt.values;
			break;
		default:
			return;
		}

		long currTime = System.currentTimeMillis();

		if ( currTime-lastUpdate > 100 && mGravity != null && mGeomagnetic != null ) {
			lastUpdate = currTime;

			boolean success = SensorManager.getRotationMatrix(R3x3, I3x3, mGravity, mGeomagnetic);
			if (success) {
	        	SensorManager.getOrientation(R3x3, orientation);
	          	azimut = orientation[0]; // orientation contains: azimut, pitch and roll
	          	// radian to degree
	          	// pi rad : 180 = a : degree
	          	// 1rad : (180/pi) = a : z
	          	// z = a * 180 / pi
	          	float z = orientation[0];
	          	if ( z < 0f ) z += (Math.PI * 2);

	          	float degree = (float)(z * 180 / Math.PI);

	          	degreeText.setText(String.format("%.2f(%.2f)", degree, azimut));

	          	surfaceView.set(orientation[0]);
	        }
		}
	}

	@Override
	public void onAccuracyChanged(Sensor arg0, int arg1) {
	}

}

class CompassView extends SurfaceView implements SurfaceHolder.Callback, Runnable {
	ExecutorService exeService = Executors.newSingleThreadExecutor();

	SurfaceHolder mHolder;
	boolean mRunning = false;
	public float z = 0f;
	
    Paint mLinePaint = new Paint();
	
	public CompassView(Context context, AttributeSet attrs) {
		super(context, attrs);

		mHolder = getHolder();
		mHolder.addCallback(this);

	    mLinePaint.setAntiAlias(true);
	    mLinePaint.setStyle(Paint.Style.STROKE);
	    mLinePaint.setStrokeWidth(3);
	}
	
	public void begin() {
		mRunning = true;
	}

	public void end() {
		mRunning = false;
		synchronized (this) {
		this.notify();
		}
	}

	public void set(float val) {
		z = val;
		synchronized (this) {
		this.notify();
		}
	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		this.begin();
		exeService.execute(this);		
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		this.end();
		exeService.shutdown();
	}
	
	@Override
	public void run() {
		Canvas canvas = null;

		while ( mRunning ) {
			try {  
				canvas = mHolder.lockCanvas();  
				synchronized (mHolder) {  
					draw(canvas);           
				}  
			}
			finally {  
				if (canvas != null) {  
					mHolder.unlockCanvasAndPost(canvas);  
				}
			}
			//
			synchronized (this) {
				try {
					this.wait();
					//Thread.sleep(500);
				} catch (InterruptedException ie) {
					ie.printStackTrace();
				}
			}
		}
	}

	public void draw(Canvas canvas) {
		//String strz = String.format("%.3f", z);
		float[] pts = new float[20];
		
		int h = canvas.getHeight();
		int w = canvas.getWidth();
		
		int lh = 300;
		int lw = 30;

		float cx = w/2;
		float cy = h/2;  // center
		
		z = -z;
		//         N
		//         /\
		//        / |\
		//       /  | \
		//       \    /
		//        \  /
		//         \/
		//         S

		pts[0] = cx;
		pts[1] = cy;
		pts[2] = (float)(cx + lh * Math.sin(z));
		pts[3] = (float)(cy - lh * Math.cos(z));
		
		pts[4] = pts[2];
		pts[5] = pts[3];
		pts[6] = (float)(cx - lw * Math.cos(z));
		pts[7] = (float)(cy - lw * Math.sin(z));
		
		pts[8] = pts[6];
		pts[9] = pts[7];
		pts[10] = (float)(cx - lh * Math.sin(z));
		pts[11] = (float)(cy + lh * Math.cos(z));

		pts[12] = pts[10];
		pts[13] = pts[11];
		pts[14] = (float)(cx + lw * Math.cos(z));
		pts[15] = (float)(cy + lw * Math.sin(z));
		
		pts[16] = pts[14];
		pts[17] = pts[15];
		pts[18] = pts[2];
		pts[19] = pts[3];

		canvas.drawColor(Color.WHITE);
		
	    mLinePaint.setColor(Color.BLACK);
	    
		canvas.drawCircle(cx, cy, lh+5, mLinePaint);
		
	    mLinePaint.setColor(Color.RED);
		canvas.drawLines(pts, 0, 8, mLinePaint);
	    mLinePaint.setColor(Color.BLUE);
		canvas.drawLines(pts, 8, 8, mLinePaint);
	    mLinePaint.setColor(Color.RED);
		canvas.drawLines(pts, 16, 4, mLinePaint);
	}

}

